<template>
  <div class="stock-kline">
    <div class="stock-list">
      <el-input
        v-model="searchQuery"
        placeholder="输入股票代码或名称搜索"
        clearable
        @input="handleSearch"
        style="margin-bottom: 10px"
      />
      <el-table
        v-loading="loading"
        :data="filteredStocks"
        style="width: 100%"
        height="400"
        @row-click="handleStockSelect"
        highlight-current-row
      >
        <el-table-column prop="symbol" label="代码" width="100" />
        <el-table-column prop="name" label="名称" width="120" />
        <el-table-column prop="area" label="地区" width="100" />
        <el-table-column prop="industry" label="行业" width="150" />
        <el-table-column prop="market" label="市场" width="100" />
      </el-table>

      <!-- 策略股票池列表 -->
      <div class="pool-title">策略股票池</div>
      <el-table
        v-loading="poolLoading"
        :data="stockPool"
        style="width: 100%"
        height="300"
        @row-click="handleStockSelect"
        highlight-current-row
      >
        <el-table-column type="index" label="序号" width="60" />
        <el-table-column prop="symbol" label="代码" width="80" />
        <el-table-column prop="name" label="名称" width="120" />
        <el-table-column prop="region" label="地区" width="80" />
        <el-table-column prop="industry" label="行业" width="120" />
        <el-table-column prop="in_date" label="入池日期" width="120">
          <template #default="scope">
            {{ formatPoolDate(scope.row.in_date) }}
          </template>
        </el-table-column>
        <!-- <el-table-column prop="out_date" label="出池日期" width="120">
          <template #default="scope">
            {{ scope.row.out_date ? formatPoolDate(scope.row.out_date) : '-' }}
          </template>
        </el-table-column> -->
      </el-table>
    </div>
    <div class="chart-container">
      <div class="controls">
        <el-select v-model="exchange" placeholder="选择交易所" style="width: 200px">
          <el-option label="深交所" value="SZSE" />
          <el-option label="上交所" value="SSE" />
        </el-select>
        <el-input v-model="symbol" placeholder="股票代码" style="width: 100px; margin: 0 10px" />
        <el-date-picker
          v-model="dateRange"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          format="YYYYMMDD"
          value-format="YYYYMMDD"
          style="width: 300px; margin-right: 10px"
        />
        <el-button type="primary" @click="fetchKLineData">查询</el-button>
      </div>
      <div ref="chartContainer" style="width: 100%; height: 700px"></div>
      
      <!-- 自定义提示框 -->
      <el-popover
        v-model:visible="tooltipVisible"
        :style="{ position: 'absolute', left: tooltipPosition.x + 'px', top: tooltipPosition.y + 'px' }"
        placement="top"
        :width="200"
        trigger="manual"
      >
        <template #default>
          <div v-if="tooltipData">
            <div style="font-size:14px;margin-bottom:5px;font-weight:bold;">
              {{ tooltipData.date }}
            </div>
            <div style="margin: 5px 0;">
              <span style="display:inline-block;width:70px;">开盘价：</span>
              <span style="display:inline-block;width:60px;">{{ tooltipData.openPrice.toFixed(2) }}</span>
            </div>
            <div style="margin: 5px 0;">
              <span style="display:inline-block;width:70px;">收盘价：</span>
              <span style="display:inline-block;width:60px;">{{ tooltipData.closePrice.toFixed(2) }}</span>
            </div>
            <div style="margin: 5px 0;">
              <span style="display:inline-block;width:70px;">最高价：</span>
              <span style="display:inline-block;width:60px;">{{ tooltipData.highPrice.toFixed(2) }}</span>
            </div>
            <div style="margin: 5px 0;">
              <span style="display:inline-block;width:70px;">最低价：</span>
              <span style="display:inline-block;width:60px;">{{ tooltipData.lowPrice.toFixed(2) }}</span>
            </div>
            <div style="margin: 5px 0;">
              <span style="display:inline-block;width:70px;">涨跌幅：</span>
              <span style="display:inline-block;width:60px;" :style="{ color: tooltipData.changeColor }">
                {{ tooltipData.changePercent }}%
              </span>
            </div>
          </div>
        </template>
      </el-popover>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import axios from 'axios'
import { debounce } from 'lodash'

export default {
  name: 'StockKLine',
  data() {
    return {
      exchange: 'SZSE',
      symbol: '000001',
      dateRange: [],
      chart: null,
      klineData: [],
      tooltipVisible: false,
      tooltipPosition: { x: 0, y: 0 },
      tooltipData: null,
      stockList: [],
      filteredStocks: [],
      searchQuery: '',
      currentStock: null,
      loading: false,
      retryCount: 0,
      maxRetries: 3,
      stockPool: [], // 策略股票池数据
      poolLoading: false // 策略股票池加载状态
    }
  },
  created() {
    // 创建防抖函数
    this.debouncedSearch = debounce(this.filterStocks, 300)
  },
  mounted() {
    this.initChart()
    this.setDefaultDateRange()
    this.fetchStockList()
    this.fetchStockPool() // 获取策略股票池数据
    window.addEventListener('keydown', this.handleKeyDown)
  },
  methods: {
    handleSearch() {
      this.loading = true
      this.debouncedSearch()
    },
    async fetchStockList() {
      this.loading = true
      try {
        const response = await axios.get('/api/stock_basic', {
          timeout: 10000 // 设置超时时间为10秒
        })
        if (response.data && Array.isArray(response.data)) {
          this.stockList = response.data
          this.filteredStocks = [...this.stockList]
          // 默认选择第一只股票
          if (this.stockList.length > 0) {
            this.handleStockSelect(this.stockList[0])
          }
          this.retryCount = 0 // 重置重试次数
        }
      } catch (error) {
        console.error('获取股票列表失败:', error)
        if (this.retryCount < this.maxRetries) {
          this.retryCount++
          console.log(`重试第 ${this.retryCount} 次`)
          setTimeout(() => this.fetchStockList(), 1000) // 1秒后重试
        } else {
          this.$message.error('获取股票列表失败，请稍后重试')
        }
      } finally {
        this.loading = false
      }
    },
    filterStocks() {
      if (!this.searchQuery) {
        this.filteredStocks = [...this.stockList]
        this.loading = false
        return
      }
      
      const query = this.searchQuery.toLowerCase()
      // 使用更高效的过滤方法
      this.filteredStocks = this.stockList.filter(stock => {
        // 优先匹配股票代码
        if (stock.symbol.toLowerCase().includes(query)) return true
        // 其次匹配股票名称
        if (stock.name.toLowerCase().includes(query)) return true
        // 最后匹配拼音首字母
        return stock.cnspell.toLowerCase().includes(query)
      })
      
      this.loading = false
    },
    handleStockSelect(stock) {
      this.currentStock = stock
      this.symbol = stock.symbol
      this.exchange = stock.exchange
      this.fetchKLineData()
    },
    initChart() {
      this.chart = echarts.init(this.$refs.chartContainer)
    },
    setDefaultDateRange() {
      const end = new Date()
      const start = new Date()
      start.setMonth(start.getMonth() - 3)  // 改为3个月
      this.dateRange = [
        this.formatDate(start),
        this.formatDate(end)
      ]
    },
    formatDate(date) {
      const year = date.getFullYear()
      const month = String(date.getMonth() + 1).padStart(2, '0')
      const day = String(date.getDate()).padStart(2, '0')
      return `${year}${month}${day}`
    },
    async fetchKLineData() {
      try {
        const [startTime, endTime] = this.dateRange
        const response = await axios.get('/api/klines', {
          params: {
            exchange: this.exchange,
            symbol: this.symbol,
            interval: 'd',
            start_time: startTime,
            end_time: endTime
          },
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
          },
          timeout: 5000
        })
        if (response.data && Array.isArray(response.data)) {
          this.klineData = response.data
          this.updateChart()
        } else {
          this.$message.error('返回数据格式不正确')
        }
      } catch (error) {
        console.error('获取K线数据失败:', error)
        if (error.code === 'ECONNREFUSED') {
          this.$message.error('无法连接到服务器，请确保后端服务已启动')
        } else if (error.response) {
          this.$message.error(`服务器错误: ${error.response.status}`)
        } else {
          this.$message.error('获取K线数据失败: ' + (error.message || '未知错误'))
        }
      }
    },
    updateChart() {
      const data = this.klineData.map(item => [
        item.datetime.split('T')[0],
        item.open_price,
        item.close_price,
        item.low_price,
        item.high_price,
        item.volume
      ])

      const option = {
        title: {
          text: `${this.symbol} K线图`
        },
        tooltip: {
          show: false
        },
        legend: {
          data: ['K线', '成交量']
        },
        grid: [
          {
            left: '10%',
            right: '8%',
            height: '60%'
          },
          {
            left: '10%',
            right: '8%',
            top: '75%',
            height: '20%'
          }
        ],
        xAxis: [
          {
            type: 'category',
            data: data.map(item => item[0]),
            scale: true,
            boundaryGap: false,
            axisLine: { onZero: false },
            splitLine: { show: false },
            splitNumber: 20
          },
          {
            type: 'category',
            gridIndex: 1,
            data: data.map(item => item[0]),
            scale: true,
            boundaryGap: false,
            axisLine: { onZero: false },
            axisTick: { show: false },
            splitLine: { show: false },
            axisLabel: { show: false },
            splitNumber: 20
          }
        ],
        yAxis: [
          {
            scale: true,
            splitArea: {
              show: true
            }
          },
          {
            scale: true,
            gridIndex: 1,
            splitNumber: 2,
            axisLabel: { show: false },
            axisLine: { show: false },
            axisTick: { show: false },
            splitLine: { show: false }
          }
        ],
        dataZoom: [
          {
            type: 'inside',
            xAxisIndex: [0, 1],
            start: 0,
            end: 100
          },
          {
            show: true,
            xAxisIndex: [0, 1],
            type: 'slider',
            top: '97%',
            start: 0,
            end: 100
          }
        ],
        series: [
          {
            name: 'K线',
            type: 'candlestick',
            data: data.map(item => [item[1], item[2], item[3], item[4]]),
            itemStyle: {
              color: '#ef232a',
              color0: '#14b143',
              borderColor: '#ef232a',
              borderColor0: '#14b143'
            }
          },
          {
            name: '成交量',
            type: 'bar',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: data.map(item => item[5])
          }
        ]
      }

      this.chart.setOption(option)
      
      // 添加鼠标事件监听
      this.chart.off('mousemove')
      this.chart.off('mouseout')
      
      this.chart.on('mousemove', (params) => {
        if (params.componentType === 'series' && params.seriesType === 'candlestick') {
          const data = params.data
          const date = this.klineData[params.dataIndex].datetime.split('T')[0]
          const openPrice = data[1]
          const closePrice = data[2]
          const lowPrice = data[3]
          const highPrice = data[4]
          
          const changePercent = ((closePrice - openPrice) / openPrice * 100).toFixed(2)
          const changeColor = changePercent >= 0 ? '#ef232a' : '#14b143'
          
          // 更新提示框数据
          this.tooltipData = {
            date,
            openPrice,
            closePrice,
            lowPrice,
            highPrice,
            changePercent,
            changeColor
          }
          
          // 更新提示框位置 - 使用鼠标位置
          if (params.event && params.event.event) {
            // 使用全局鼠标位置
            this.tooltipPosition = {
              x: params.event.event.clientX,
              y: params.event.event.clientY - 10
            }
            
            // 显示提示框
            this.tooltipVisible = true
          }
        }
      })
      
      this.chart.on('mouseout', () => {
        this.tooltipVisible = false
      })
    },
    handleKeyDown(event) {
      if (event.key === 'ArrowUp') {
        this.zoomChart(0.9)
      } else if (event.key === 'ArrowDown') {
        this.zoomChart(1.1)
      }
    },
    zoomChart(scale) {
      if (!this.chart) return
      
      const option = this.chart.getOption()
      const dataZoom = option.dataZoom[0]
      const currentRange = dataZoom.end - dataZoom.start
      const newRange = currentRange * scale
      
      if (newRange > 5 && newRange < 100) {
        const center = (dataZoom.start + dataZoom.end) / 2
        const halfRange = newRange / 2
        
        option.dataZoom[0].start = Math.max(0, center - halfRange)
        option.dataZoom[0].end = Math.min(100, center + halfRange)
        option.dataZoom[1].start = option.dataZoom[0].start
        option.dataZoom[1].end = option.dataZoom[0].end
        
        this.chart.setOption(option)
      }
    },
    // 获取策略股票池数据
    async fetchStockPool() {
      this.poolLoading = true
      try {
        const response = await axios.get('/api/stock_pool', {
          timeout: 10000
        })
        if (response.data && Array.isArray(response.data)) {
          this.stockPool = response.data
        }
      } catch (error) {
        console.error('获取策略股票池失败:', error)
        this.$message.error('获取策略股票池失败，请稍后重试')
      } finally {
        this.poolLoading = false
      }
    },
    // 格式化股票池日期
    formatPoolDate(dateString) {
      if (!dateString) return '-'
      const date = new Date(dateString)
      return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
    }
  },
  beforeUnmount() {
    if (this.chart) {
      this.chart.dispose()
    }
    window.removeEventListener('keydown', this.handleKeyDown)
  }
}
</script>

<style scoped>
.stock-kline {
  padding: 20px;
  position: relative;
  display: flex;
  gap: 20px;
}
.stock-list {
  width: 600px;
  border-right: 1px solid #eee;
  padding-right: 20px;
}
.chart-container {
  flex: 1;
}
.controls {
  margin-bottom: 20px;
  display: flex;
  align-items: center;
}
.pool-title {
  margin: 20px 0 10px;
  font-size: 16px;
  font-weight: bold;
  color: #333;
}
</style> 